package com.yitong.main.service;

import com.yitong.PluginMainApplication;
import com.yitong.main.jpa.YpluginRepository;
import com.yitong.spiboot.BootService;
import com.yitong.spiboot.entity.Yplugin;
import com.yitong.spiboot.entity.YpluginEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.data.domain.Example;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.ServletContext;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class ToolsService {
    @Autowired
    YpluginRepository ypluginRepository;

    private static Map <String, YpluginEvent> ypluginEventMap = new HashMap <>();

    @EventListener( ConfigurableApplicationContext.class )
    public void initPlugin(ConfigurableApplicationContext run){
        Yplugin yplugin = new Yplugin();
        yplugin.setStatus( 1 );
        Example <Yplugin> ypluginExample = Example.of( yplugin );
        List <Yplugin> all = ypluginRepository.findAll( ypluginExample );
        all.forEach( e->{
            start( e.getYid() );
        } );
    }
    @EventListener( YpluginEvent.class )
    public void onApplicationEvent(YpluginEvent ypluginEvent) throws InterruptedException {
        log.info( "集成Springboot插件：{}" , ypluginEvent.getPid() );
        ypluginEventMap.put( ypluginEvent.getPid(), ypluginEvent );
        Yplugin yplugin = ypluginRepository.findById( ypluginEvent.getPid() ).get();
        yplugin.setStatus( 1 );
        ypluginRepository.save( yplugin );
        System.gc();
    }

    @Async
    public void start(String pid) {
        ApplicationContext applicationContext = PluginMainApplication.getApplication();
        ServletContext bean = applicationContext.getBean( ServletContext.class );
        List <BootService> serviceLoader = SpringFactoriesLoader.loadFactories( BootService.class ,null);

        for (BootService service1 : serviceLoader) {
            service1.onStartup( pid, bean, applicationContext );
        }
    }

    public void stop(String pid) {
        YpluginEvent ypluginEvent = ypluginEventMap.get( pid );
        ConfigurableApplicationContext applicationContext1 = ypluginEvent.getApplicationContext();
        ServletContext servletContext = ypluginEvent.getServletContext();
        try {
            Field fieldApplicationContext = servletContext.getClass().getDeclaredField( "context" );//利用反射获取ApplicationContext对象
            fieldApplicationContext.setAccessible( true );//使私有可获取
            org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) fieldApplicationContext.get( servletContext );//获取到ApplicationContext对象

            Field fieldStandardContext = applicationContext.getClass().getDeclaredField( "context" );//利用反射获取StandardContext对象
            fieldStandardContext.setAccessible( true );//使私有可获取
            StandardContext context = (StandardContext) fieldStandardContext.get( applicationContext );//获取到StandardContext对象
            DispatcherServletRegistrationBean bean = ypluginEvent.getApplicationContext().getBean( DispatcherServletRegistrationBean.class
            );
            Wrapper wrapper = (Wrapper) context.findChild( bean.getServletName() );
            if (wrapper != null) {
//                wrapper.stop();
//

                bean.getUrlMappings().forEach( e->{
                    context.removeServletMapping( e );
                } );
                context.removeChild( wrapper );
//                context.removeFilterDef(  );

            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException( e );
        } catch (IllegalAccessException e) {
            throw new RuntimeException( e );
        }
        applicationContext1.close();
        Yplugin yplugin = ypluginRepository.findById( ypluginEvent.getPid() ).get();
        yplugin.setStatus( 0 );
        ypluginRepository.save( yplugin );
        System.gc();
    }

    public Object getBeans(String pid) {
        YpluginEvent ypluginEvent = ypluginEventMap.get( pid );
        return ypluginEvent.getApplicationContext().getBeanDefinitionNames();
    }
}
